home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3.2 / Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO / packet / n17jsrc / forward.c < prev    next >
C/C++ Source or Header  |  1991-10-16  |  25KB  |  870 lines

  1. /* Some of the code in this file was originally based on the following file:
  2.  * gateway.c : Paul Healy, EI9GL, 900818
  3.  *
  4.  * Rewrote forwarding mechanism to use "X-Forwarded-To" paradigm instead of
  5.  * "X-BBS-To", added timer support, etc.  Anders Klemets, SM0RGV, 901009.
  6.  */
  7.  /* Mods by G1EMM */
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11. #include <time.h>
  12. #include "global.h"
  13. #include "config.h"
  14. #include "bm.h"
  15. #include "mailbox.h"
  16. #include "smtp.h"
  17. #include "cmdparse.h"
  18. #include "proc.h"
  19. #include "socket.h"
  20. #include "timer.h"
  21. #include "usock.h"
  22. #include "netuser.h"
  23. #include "ax25.h"
  24. #include "netrom.h"
  25. #include "nr4.h"
  26. #include "files.h"
  27.  
  28. #define ISPROMPT(s)    (strlen(s) > 1 && s[strlen(s)-2] == '>')
  29. static struct timer fwdtimer;
  30.  
  31. static char *findident __ARGS((char *str, int n, char *result));
  32. static void sendmsg __ARGS((struct mbx *m,int msgn));
  33. static char *mbxtime __ARGS((char *line));
  34. static int fwdinit __ARGS((struct mbx *m));
  35. static char *fwdanybbs __ARGS((struct mbx *m));
  36. static int timeok __ARGS((char *line));
  37. static void fwdtick __ARGS((void *v));
  38. static int isconnbbs __ARGS((struct mbx *m));
  39. static void startfwd __ARGS((int a,void *v1,void *v2));
  40. static int openconn __ARGS((int argc,char *argv[],void *p));
  41. static int sendmsgtobbs __ARGS((struct mbx *m,int msgn,char *dest,int bulletin));
  42. static int makecl __ARGS((struct mbx *m,int msgn,char *dest,char *line,char *subj,int bulletin));
  43. static char *grabtext __ARGS((char *from,char *to,int marker));
  44.  
  45. /***************************************************************************
  46.    findident copies the 'n'th alphanumeric sequence from 'str' to result.
  47.    It returns a ptr to result. It returns "\0" for missing identifier etc.
  48.    Uses isalnum macro to decide on alphanumeric/non-alnum status.
  49. */
  50. static char *
  51. findident(str, n, result)
  52. char *str, *result;
  53. int n;
  54. {
  55.    int count; /* current identifier */
  56.    count = 0;
  57.    *result = '\0';
  58.    while ( (count<n) && (*str!='\0') ) { /* Process alnum or non alnum seq */
  59.       while ( (*str!='\0') && (!isalnum(*str)) ) /* Get rid of ';:.@%"# etc */
  60.          str++;
  61.       if ( (str!='\0') && isalnum(*str) ) { /* this is an alnum seq */
  62.          count++;
  63.          while ( (*str!='\0') && (isalnum(*str) || (*str=='_')) )
  64.             if (count==n)
  65.                *result++ = *str++;
  66.             else str++;
  67.          if (count==n)
  68.             *result = '\0';
  69.          }
  70.       }
  71.    return result;
  72. }
  73. /**************************************************************************/
  74. static void
  75. sendmsg(m,msgn)
  76. struct mbx *m;
  77. int msgn;
  78. {
  79.     char buf[LINELEN], tb[LINELEN], *cp;
  80.     int len, rec = 0;
  81.     long cnt;
  82.     fseek(m->mfile,m->mbox[msgn].start,0);
  83.     cnt = m->mbox[msgn].size;
  84.  
  85.     /* If the data part of the message starts with "R:" the RFC-822
  86.      * headers will not be forwarded. Instead we will add an R:
  87.      * line of our own.
  88.      */
  89.     for(;;) {
  90.         if(fgets(buf,sizeof(buf),m->mfile) == NULLCHAR)
  91.             break;
  92.         cnt -= strlen(buf);
  93.         if(rec == 1) {    /* look at the line following Received: */
  94.              ++rec;
  95.              if((cp = strchr(buf,';')) != NULLCHAR){
  96.               strcpy(tb,cp+1);     /* get the date of receipt */
  97.               ++rec;
  98.              }
  99.         }
  100.         /* The first Received: line is the one that we have added */
  101.         if(!rec && htype(buf) == RECEIVED)
  102.              ++rec;
  103.         if(*buf == '\n') {
  104.              if(rec == 3 && cnt > 1) {
  105.               fread(buf,1,2,m->mfile);
  106.               cnt -= 2;
  107.               if(strncmp(buf,"R:",2) == 0) {
  108.                    pax25(buf,Mycall);
  109.                    if((cp = strchr(buf,'-')) != NULLCHAR)
  110.                     *cp = '\0';    /* remove SSID */
  111.                    usprintf(m->user,"R:%s @%s %s (%s)\nR:",
  112.                     mbxtime(tb),buf,Hostname,Version);
  113.                    break;
  114.               }
  115.              }
  116.              /* Start over, forwarding the RFC-822 headers */
  117.              fseek(m->mfile,m->mbox[msgn].start,0);
  118.              cnt = m->mbox[msgn].size;
  119.              rec = 0;
  120.              break;
  121.         }
  122.        }
  123.     while(rec != 3) {    /* Forward the RFC-822 headers */
  124.         if(fgets(buf,sizeof(buf),m->mfile) == NULLCHAR)
  125.             break;
  126.         cnt -= strlen(buf);
  127.         switch(htype(buf)) {
  128.         case XFORWARD: /* Do not forward the "X-Forwarded-To:" lines */
  129.         case STATUS:   /* Don't forward the "Status:" line either */
  130.              break;
  131.         default:
  132.         /* Don't forward the "From " line either - make it ">From " G1EMM */
  133.              if(strlen(buf) >= 5 && strncmp(buf,"From ",5) == 0) {
  134.             cp = strdup(buf);
  135.             strcpy(buf,">");
  136.             strcat(buf,cp);
  137.             free(cp);
  138.              }
  139.              usputs(m->user,buf);
  140.         }
  141.         if(*buf == '\n')    /* last header line */
  142.             break;
  143.     }
  144.     do {    /* the rest of the message is treated below */
  145.         len = min(cnt,sizeof(buf)-1);
  146.         if(fread(buf,1,len,m->mfile) != len)
  147.             break;
  148.         cnt -= len;
  149.         buf[len] = '\0';
  150.         usputs(m->user,buf);
  151.     } while(cnt);
  152. }
  153.  
  154. /* Parse a line for date and time in Arpanet format
  155.  * (Day, day Month year hh:mm:ss Zone) and return it in mailbox format
  156.  * (yymmdd/hhmmz)
  157.  */
  158. static char *
  159. mbxtime(line)
  160. char *line;
  161. {
  162.      extern char *Months[];
  163.      static char buf[12];
  164.      char *cp;
  165.      int i, day;
  166.      cp = line;
  167.      while(isspace(*cp))    /* skip initial blanks */
  168.       ++cp;
  169.      if(*cp == '\0')
  170.       return NULLCHAR;
  171.      if(strlen(cp) < 22)
  172.       return NULLCHAR;
  173.      cp += 5;
  174.      day = atoi(cp);
  175.      if(*(++cp) != ' ')
  176.       ++cp;
  177.      ++cp;
  178.      for(i=0; i < 12; ++i)
  179.       if(strnicmp(Months[i],cp,3) == 0)
  180.            break;
  181.      if(i == 12)
  182.       return NULLCHAR;
  183.      sprintf(buf,"%02d%02d%02d/%02d%02d%c",atoi(cp + 4),++i,day,atoi(cp + 7),
  184.          atoi(cp + 10), (strnicmp(cp + 16,"GMT",3) &&
  185.                  strnicmp(cp + 16,"UTC",3)) ? ' ' : 'z');
  186.      return buf;
  187. }
  188.      
  189. static char *
  190. grabtext(from, to, marker)
  191. char *from, *to;
  192. int marker;
  193. {
  194.    while (*from!=marker)
  195.       *to++ = *from++;
  196.    *to = '\0';
  197.    return from+1;
  198. }
  199.  
  200. /* Makes a command line and returns -1 if the message cannot be sent. */
  201. static int
  202. makecl(m, msgn, dest, line, subj, bulletin)
  203. struct mbx *m;
  204. int msgn;        /* Message number */
  205. char *dest;        /* Destination address to use instead of To: line */
  206. char *line, *subj;    /* Buffers to keep command line and subject */
  207. int bulletin;        /* True if message is in public message area */
  208. {
  209.    char bid[LINELEN], to[LINELEN], atbbs[LINELEN], from[LINELEN],
  210.     buf[LINELEN], *cp;
  211.    if(m->mfile == NULLFILE)
  212.     return -1;
  213.    if(!bulletin && (m->mbox[msgn].status & BM_READ))
  214.     return -1;    /* the message was already read */
  215.    fseek(m->mfile,m->mbox[msgn].start,0);
  216.    *bid = *to = *atbbs = *from = '\0';
  217.    if(subj != NULLCHAR)
  218.     *subj = '\0';
  219.    m->stype = bulletin ? 'B' : 'P';    /* default to SB or SP */
  220.    while (fgets(buf,sizeof(buf),m->mfile)) {
  221.       if (buf[0] == '\n')
  222.          break; /* envelope finished */
  223.       switch (htype(buf)) {
  224.       case TO:
  225.         /* The following code tries to parse "To: " lines where the
  226.          * address looks like any of the following: "to@atbbs",
  227.          * "<to@atbbs>", "<to%atbbs@host>" and with possible spaces
  228.          * surrounding the '<>' characters.
  229.          */
  230.         if((cp = getaddress(buf,0)) == NULLCHAR)
  231.         break;
  232.         strcpy(to,cp);
  233.         if((cp = strchr(to,'%')) != NULLCHAR) { /* look for a '%' */
  234.          strcpy(atbbs,cp + 1);
  235.          *cp = '\0';    /* "to" ends at the '%' character */
  236.         }
  237.         else {    /* no '%' but maybe a '@'? */
  238.          if((cp = strchr(to,'@')) != NULLCHAR) {
  239.               strcpy(atbbs,cp + 1);
  240.               *cp = '\0';    /* "to" ends at the '@' character */
  241.          }
  242.         }
  243.         if(*atbbs != '\0')        /* either '%' or '@' found */
  244.          /* cut "atbbs" at the first '@' character */
  245.          for(cp = atbbs; *cp != '\0'; ++cp)
  246.               if(*cp == '@') {
  247.                *cp = '\0';
  248.                break;
  249.               }
  250.         /* "to" or "atbbs" should not be more than 6 characters (ALEN).
  251.          * If "to" is too long, it might simply be because the area name
  252.          * is longer than 6 characters, but it might also be because
  253.          * the address on the To: line is in an obscure format that we
  254.          * failed to parse (eg '!' character notation.)
  255.          */
  256.         if(strlen(to) > ALEN) {
  257.         /* Play safe and set "to" and "atbbs" to the area name */
  258.         strcpy(to,m->area);
  259.         strcpy(atbbs,m->area);
  260.               }
  261.         if(*atbbs == '\0')
  262.         strcpy(atbbs,to);
  263.               to[ALEN] = '\0';
  264.         /* Only if the BBS supports "hierarchical routing designators"
  265.          * is the atbbs field allowd to be longer than 6 characters and
  266.          * have dots in it.
  267.          */
  268.         if((m->sid & MBX_HIER_SID) == 0) {
  269.          atbbs[ALEN] = '\0';    /* 6 character limit */
  270.          if((cp = strchr(atbbs,'.')) != NULLCHAR)
  271.               *cp = '\0';    /* cut "atbbs" at first dot */
  272.         }
  273.             break;
  274.       case MSGID:
  275.         /* The following code distinguishes between two different types
  276.          * of Message-IDs: <abcde@callsign.bbs> and <abcde@host.domain>.
  277.          * The first type is converted to $abcde and the second to
  278.          * $abcde_host.domain. This preserves compability with BBSes.
  279.          */
  280.         if((cp = getname(buf)) == NULLCHAR)
  281.          break;
  282.         bid[0] = '$';
  283.         strcpy(&bid[1],cp);
  284.               cp = strchr(bid,'@');
  285.         /* A trailing ".bbs" indicates that the Message-ID was generated
  286.          * from a BBS style message, and not a RFC-822 message.
  287.          */
  288.         if(cp != NULLCHAR && stricmp(&bid[strlen(bid) - 4], ".bbs") == 0)
  289.         *cp = '\0';
  290.         else
  291.         *cp = '_';
  292.         bid[13] = '\0';    /* BIDs should be no longer than 13 bytes */
  293.               break;
  294.       case SUBJECT:
  295.         if(subj != NULLCHAR)
  296.               (void) grabtext(buf+9, subj, '\n');
  297.             break;
  298.       case FROM:
  299.         if((cp = getaddress(buf,0)) != NULLCHAR) {
  300.         findident(cp, 1, from);        /* cp points to from@domain */
  301.         from[ALEN] = '\0';    /* 6 character limit */
  302.         }
  303.             break;
  304.       case XFORWARD:
  305.         if((cp = getaddress(buf,0)) == NULLCHAR)
  306.          break;
  307.         if(stricmp(m->name,cp) == 0)
  308.         /* This message has already been forwarded, abort */
  309.         return -1;
  310.         break;
  311.       case BBSTYPE:
  312.         m->stype = buf[16];
  313.         break;
  314.       default:
  315.         break;
  316.       }
  317.    }
  318.    /* Check for an invalid RFC-822 header */
  319.    if((to[0] == '\0' && ((dest != NULLCHAR && *dest == '\0') ||
  320.       dest == NULLCHAR)) || from[0] == '\0')
  321.     return -1;
  322.  
  323.    if(line != NULLCHAR) {
  324.     if(dest != NULLCHAR && *dest != '\0'){
  325.          /* strip off hierarchical routing designators from the predefined
  326.           * destination address if they are not supported
  327.           */
  328.          if((m->sid & MBX_HIER_SID) == 0 && (cp = strchr(dest,'.')) !=
  329.            NULLCHAR)
  330.         *cp = '\0';
  331.          sprintf(line, "S%c %s < %s ", m->stype, dest, from);
  332.     }
  333.     else
  334.          sprintf(line, "S%c %s @ %s < %s ", m->stype, to, atbbs, from);
  335.     if(bulletin & (m->sid & MBX_SID))
  336.          strcat(line,bid);
  337.     strcat(line,"\n");
  338.    }
  339.    return 0;
  340. }
  341.  
  342. static int /* 0 = ok, -1 = problem so disc */
  343. sendmsgtobbs(m, msgn, dest, bulletin)
  344. struct mbx *m;
  345. int msgn;
  346. char *dest;        /* Optional destination address to override To: line */
  347. int bulletin;
  348. {
  349.    int result = -1;
  350.    char line[64], subj[256];
  351.    if(makecl(m, msgn, dest, line, subj, bulletin) == -1)
  352.     return 0;    /* do not forward this particular message */
  353.    tputs(line);         /* Send mail offer to bbs */
  354.    rip(line);
  355.    usflush(m->user);
  356.    if (recvline (m->user, m->line, MBXLINE) != -1 ) {
  357.       if (m->line[0] == 'O' || m->line[0] == 'o' || (m->sid & MBX_SID) == 0) {
  358.      /* Got 'OK' or any line if the bbs is unsofisticated */
  359.          tprintf("%s\n", subj);
  360.      sendmsg(m,msgn);    /* send the message */
  361.          tputs("/EX\n"); /* was 0x1a */
  362.          usflush(m->user);
  363.            /* get F> for a good deliver */
  364.            while (recvline (m->user, m->line, MBXLINE) != -1 )
  365.         if (ISPROMPT(m->line)) {
  366.             log(m->user,"MBOX bbs mail sent: %s ", line);
  367.             if(bulletin)
  368.                 m->mbox[msgn].status |= BM_FORWARDED;
  369.             else
  370.                 m->mbox[msgn].status |= BM_DELETE;
  371.             m->change = 1;
  372.             result = 0;
  373.             break;
  374.         }
  375.       }
  376.       else { /* OK response not received from bbs */
  377.        if (m->line[0] == 'N' || m->line[0] == 'n') { /* 'NO' respone */
  378.               log(m->user,"MBOX bbs mail refused: %s\n     %s",line,m->line);
  379.         /* Mark refused message as forwarded if it is a bulletin.
  380.          * The message was probably a duplicate. Non-bulletin
  381.          * messages are sent without BID, so they cannot be dected
  382.          * as duplicates. The reason why it was refused is probably
  383.          * because the address was invalid. Retry later.
  384.          */
  385.         if(bulletin){
  386.             m->mbox[msgn].status |= BM_FORWARDED;
  387.             m->change = 1;
  388.         }
  389.           }
  390.             /* should get a F> here */
  391.           while (recvline (m->user, m->line, MBXLINE) != -1 )
  392.               if (ISPROMPT(m->line)) {
  393.                   result = 0;
  394.             break;
  395.               }
  396.       }
  397.    } /* OK or NO here */
  398.    return result;
  399. }
  400.  
  401. /* This is the main entry point for reverse forwarding. It is also used
  402.  * for normal, "forward", forwarding.
  403.  */
  404. int
  405. dorevfwd(argc,argv,p)
  406. int argc;
  407. char *argv[];
  408. void *p;
  409. {
  410.     char oldarea[64], *cp;
  411.     struct mbx *m;
  412.     int i, bulletin, err = 0;
  413.     m = (struct mbx *)p;
  414.     log(m->user,"MBOX forwarding mail to: %s ", m->name);
  415.     /* indicate we are doing reverse forwarding, if we are not already
  416.      * doing normal forwarding.
  417.      */
  418.     if(m->state != MBX_FORWARD)
  419.         m->state = MBX_REVFWD;
  420.     if(fwdinit(m) != -1) {
  421.         strcpy(oldarea,m->area);
  422.         while(!err && fgets(m->line,MBXLINE,m->tfile) != NULLCHAR) {
  423.             if(*m->line == '-')    /* end of record reached */
  424.                 break;
  425.             rip(m->line);        /* adds extra null at end */
  426.             cp = strchr(m->line,' '); /* remove trailing blanks */
  427.             if(cp != NULLCHAR)
  428.                 *cp = '\0';
  429.             if((cp = strchr(m->line,'\t')) != NULLCHAR)
  430.                 *cp = '\0';
  431.             if(*m->line == '\0' || *m->line == '.')
  432.                 continue;
  433.             changearea(m,m->line);
  434.             bulletin = isarea(m->line);    /* public area */
  435.             /* get the optional destination field, cp will point
  436.              * at null byte if it is missing.
  437.              */
  438.             cp = &m->line[strlen(m->line)] + 1;
  439.             while(*cp != '\0' && isspace(*cp)) /* strip blanks */
  440.                  ++cp;
  441.             cp = strdup(cp);
  442.             for(i=1; i<=m->nmsgs; i++)
  443.                 if(sendmsgtobbs(m, i, cp, bulletin) == -1) {
  444.                     err = 1;    /* abort */
  445.                     break;
  446.                 }
  447.             free(cp);
  448.         }
  449.         fclose(m->tfile);
  450.         m->tfile = NULLFILE;
  451.         if(*oldarea != '\0')
  452.             changearea(m,oldarea);
  453.     }
  454.     if(m->state == MBX_FORWARD)
  455.         return 0;
  456.     tprintf("*** Done\n");
  457.     if((m->sid & MBX_RLI_SID))    /* disconnect if it is a W0RLI bbs */
  458.         return domboxbye(0,NULL,m);
  459.     return 0;
  460. }
  461.  
  462. /* Read the forward file for a record for the connected BBS. If found,
  463.  * return 1 if this is the right time to forward, m->tfile is left pointing
  464.  * at the first message area to be forwarded.
  465.  */
  466. static int
  467. fwdinit(m)
  468. struct mbx *m;
  469. {
  470.     char host[80];
  471.     int start = 1;
  472.     if((m->tfile = fopen(Forwardfile,READ_TEXT)) == NULLFILE)
  473.         return -1;
  474.     while(fgets(m->line,MBXLINE,m->tfile) != NULLCHAR) {
  475.         if(*m->line == '\n')
  476.             continue;
  477.         /* lines starting with '-' separate the forwarding records */
  478.         if(*m->line == '-') {
  479.             start = 1;
  480.             continue;
  481.         }
  482.         if(start) {
  483.             start = 0;
  484.             /* get the name of this forwarding record */
  485.             findident(m->line,1,host);
  486.             if(stricmp(m->name,host) == 0) {
  487.                 if(!timeok(m->line))
  488.                     break;
  489.                 /* eat the connect command line */
  490.                 fgets(m->line,MBXLINE,m->tfile);
  491.                 return 0;
  492.             }
  493.         }
  494.     }
  495.     fclose(m->tfile);
  496.     m->tfile = NULLFILE;
  497.     return -1;
  498. }
  499. /* Read the forward file for a record for the connected BBS. If found,
  500.  * determine if this is the right time to forward, and return the command
  501.  * line to establish a forwarding connection. m->tfile is left pointing
  502.  * at the first message area to be forwarded.
  503.  */
  504. static char *
  505. fwdanybbs(m)
  506. struct mbx *m;
  507. {
  508.     char host[80];
  509.     int start = 1;
  510.     if(m->tfile == NULLFILE && (m->tfile = fopen(Forwardfile,READ_TEXT))
  511.                     == NULLFILE)
  512.         return NULLCHAR;
  513.     while(fgets(m->line,MBXLINE,m->tfile) != NULLCHAR) {
  514.         if(*m->line == '\n')
  515.             continue;
  516.         /* lines starting with '-' separate the forwarding records */
  517.         if(*m->line == '-') {
  518.             start = 1;
  519.             continue;
  520.         }
  521.         if(start) {
  522.             start = 0;
  523.             /* get the name of this forwarding record */
  524.             findident(m->line,1,host);
  525.             strcpy(m->name,host);
  526.             if(!timeok(m->line))
  527.                 continue;    /* too late or too early */
  528.             /* get the connect command line */
  529.             fgets(m->line,MBXLINE,m->tfile);
  530.             return strdup(m->line);
  531.         }
  532.     }
  533.     fclose(m->tfile);
  534.     m->tfile = NULLFILE;
  535.     return NULLCHAR;
  536. }
  537.  
  538. /* get any groups of four digits that specify the begin and ending hours of
  539.  * forwarding. Returns 1 if forwarding may take place.
  540.  */
  541. static int
  542. timeok(line)
  543. char *line;
  544. {
  545.     char hours[80], *now;
  546.     long t;
  547.     int t1, t2, pos = 2;
  548.     findident(line,pos++,hours);
  549.     if(*hours == '\0')
  550.         return 1;    /* no digits default to 0023, ie. anytime */
  551.     time(&t);
  552.     now = ctime(&t) + 11;
  553.     *(now + 2) = '\0';
  554.     while(*hours != '\0') {
  555.         t1 = (*hours - '0') * 10 + (*(hours+1) - '0');
  556.         t2 = (*(hours+2) - '0') * 10 + (*(hours+3) - '0');
  557.         if(atoi(now) >= t1 && atoi(now) <= t2)
  558.             return 1;        /* right in time */
  559.         findident(line,pos++,hours);    /* get next group if any */
  560.     }
  561.     return 0;    /* too early or too late */
  562. }
  563.  
  564. int
  565. dombtimer(argc,argv,p)
  566. int argc;
  567. char *argv[];
  568. void *p;
  569. {
  570.     if(argc < 2){
  571.         tprintf("Forwarding timer: %lu/%lu\n",
  572.         read_timer(&fwdtimer)/1000L,
  573.         dur_timer(&fwdtimer)/1000L);
  574.         return 0;
  575.     }
  576.     fwdtimer.func = (void (*)())fwdtick;/* what to call on timeout */
  577.     fwdtimer.arg = NULL;        /* dummy value */
  578.     set_timer(&fwdtimer,atol(argv[1])*1000L); /* set timer duration */
  579.     start_timer(&fwdtimer);        /* and fire it up */
  580.     return 0;
  581. }
  582.  
  583. int
  584. dombkick(argc,argv,p)
  585. int argc;
  586. char *argv[];
  587. void *p;
  588. {
  589.     fwdtick(NULL);
  590.     return 0;
  591. }
  592.  
  593. /* called when the forward timer expires or explicitly by dombkick() */
  594. static void
  595. fwdtick(v)
  596. void *v;
  597. {
  598.     char *cc, *cp;
  599.     struct mbx *m;
  600.     int i, bulletin, skip = 0;
  601.  
  602.     if(Mtrace)
  603.         tprintf("mailbox: forward started\n");
  604.     /* restart the timer */
  605.     start_timer(&fwdtimer);
  606.     if((m = newmbx()) == NULLMBX){
  607.         if(Mtrace)
  608.             tprintf("mailbox: unable to start new maibox\n");
  609.         return;
  610.     }
  611.     m->user = Curproc->output;
  612.     m->state = MBX_TRYING;
  613.     while((cc = fwdanybbs(m)) != NULLCHAR) {
  614.         if(isconnbbs(m)) /* already connected to this BBS, skip it */
  615.             skip = 1;
  616.         while(fgets(m->line,MBXLINE,m->tfile) != NULLCHAR) {
  617.             if(*m->line == '-') {    /* end of record reached */
  618.                 skip = 0;
  619.                 break;
  620.             }
  621.             if((cp = strchr(m->line,' ')) != NULLCHAR)
  622.                 *cp = '\0';
  623.             if((cp = strchr(m->line,'\t')) != NULLCHAR)
  624.                 *cp = '\0';
  625.             if(skip || *m->line == '\0' || *m->line == '.')
  626.                 continue;
  627.             rip(m->line);
  628.             changearea(m,m->line);
  629.             bulletin = isarea(m->line);    /* public area */
  630.             /* check if there are any messages in this area
  631.              * that need to be forwarded.
  632.              */
  633.             for(i=1; i<=m->nmsgs; i++)
  634.                 if(makecl(m, i, NULLCHAR, NULLCHAR, NULLCHAR,
  635.                    bulletin) == 0) {
  636.                     if(Mtrace)
  637.                        tprintf("mailbox: forwarding to %s\n"
  638.                         ,m->name);
  639.                     newproc("Mbox forwarding", 2048,
  640.                         startfwd, 0, (void *)cc,
  641.                         (void *)strdup(m->name),0);
  642.                     skip = 1;
  643.                     cc = NULLCHAR;
  644.                     break;
  645.                 }
  646.         }
  647.         free(cc);
  648.     }
  649.     exitbbs(m);
  650. }
  651.  
  652. /* returns 1 if m->name matches the name of another connected mailbox. */
  653. static int
  654. isconnbbs(m)
  655. struct mbx *m;
  656. {
  657.     int i;
  658.     for(i = 0; i < NUMMBX; ++i)
  659.         if(Mbox[i] != NULLMBX && Mbox[i] != m &&
  660.             stricmp(m->name,Mbox[i]->name) == 0)
  661.                 return 1;
  662.     return 0;
  663. }
  664.  
  665. /* possible commands on the command line in the forwarding file */
  666. static struct cmds cfwdcmds[] = {
  667.     "tcp",        openconn,    0, 0, NULLCHAR,
  668.     "telnet",    openconn,    0, 0, NULLCHAR,
  669. #ifdef AX25
  670.     "ax25",        openconn,    0, 0, NULLCHAR,
  671.     "connect",    openconn,    0, 0, NULLCHAR,
  672. #endif
  673. #ifdef NETROM
  674.     "netrom",    openconn,    0, 0, NULLCHAR,
  675. #endif
  676.     NULLCHAR
  677. };
  678.  
  679. /* this function is called whenever the forwarding timer expires */
  680. static void
  681. startfwd(a,v1,v2)
  682. int a;
  683. void *v1, *v2;
  684. {
  685.     struct mbx *m;
  686.     char *cc;
  687.     cc = (char *) v1;
  688.     if((m = newmbx()) == NULLMBX) {
  689.         free(cc);
  690.         free((char *)v2);
  691.         return;
  692.     }
  693.     strcpy(m->name,(char *)v2);
  694.     free((char *)v2);
  695.     m->state = MBX_TRYING;
  696.     /* open the connection, m->user will be the new socket */
  697.     if(cmdparse(cfwdcmds,cc,(void *)m) == -1) {
  698.         free(cc);
  699.         exitbbs(m);
  700.         if(Mtrace)
  701.             tprintf("mailbox: unknown forwarding protocol\n");
  702.         return;
  703.     }
  704.     free(cc);
  705.     m->state = MBX_FORWARD;
  706.     sockowner(m->user,Curproc);
  707.     close_s(Curproc->output);
  708.     close_s(Curproc->input);
  709.     /* m->user will be closed automatically when this process exits */
  710.     Curproc->output = Curproc->input = m->user;
  711.     /* We'll do our own flushing right before we read input */
  712.     setflush(m->user,-1);
  713.  
  714.     if(fwdinit(m) == -1) {
  715.         /* it is probably not the right time to forward anymore */
  716.         exitbbs(m);
  717.         return;
  718.     }
  719.     /* read the connect script. Lines starting with a dot will be sent
  720.      * to the remote BBS.
  721.      */
  722.     while(fgets(m->line,MBXLINE,m->tfile) != NULLCHAR)
  723.         if(*m->line == '.')
  724.             tputs(m->line + 1);
  725.         else
  726.             break;
  727.     usflush(m->user);
  728.     fclose(m->tfile);
  729.     m->tfile = NULLFILE;
  730.  
  731.     /* read the initial output from the bbs, looking for the SID */
  732.     for(;;) {
  733.         if(recvline(m->user,m->line,MBXLINE) == -1) {
  734.             exitbbs(m);
  735.             return;
  736.         }
  737.         if(ISPROMPT(m->line))
  738.             break;
  739.         if(*m->line == '[') {        /* parse the SID */
  740.             rip(m->line);
  741.             mbx_parse(m);
  742.             continue;
  743.         }
  744.     }
  745.     /* Now sync the two ends as telnet password messes them up */
  746.     if(socklen(m->user,0))        /* discard any remaining input */
  747.         recv_mbuf(m->user,NULL,0,NULLCHAR,0);
  748.  
  749.     /* send our SID if the peer announced its SID */
  750.     if(m->sid & MBX_SID) {
  751.         tputs("[NET-H$]\n");
  752.         usflush(m->user);
  753.         for(;;) {
  754.             if(recvline(m->user,m->line,MBXLINE) == -1) {
  755.                 exitbbs(m);
  756.                 return;
  757.             }
  758.             if(ISPROMPT(m->line))
  759.                 break;
  760.         }
  761.     }
  762.     /* start the actual forwarding */
  763.     dorevfwd(0,NULL,(void *)m);
  764.     /* ask for reverse forwarding or just disconnect */
  765.     if(((m->sid & MBX_SID) && tputs("F>\n") == -1) ||
  766.        (m->sid & MBX_SID) == 0) {
  767.         exitbbs(m);
  768.         close_s(Curproc->output);
  769.         return;
  770.     }
  771.     usflush(m->user);
  772.     /* parse the commands that are are received during reverse
  773.      * forwarding.
  774.      */
  775.     while(recvline(m->user,m->line,MBXLINE) > 0) {
  776.         rip(m->line);
  777.         if(mbx_parse(m) == 2)    /* got the "*** Done" command */
  778.             break;
  779.         tputs("F>\n");
  780.         usflush(m->user);
  781.     }
  782.     exitbbs(m);
  783.     close_s(Curproc->output);
  784. }
  785.  
  786. /* open a network connection based upon information in the cc line.
  787.  * m->user is set to the socket number.
  788.  */
  789. static int
  790. openconn(argc,argv,p)
  791. int argc;
  792. char *argv[];
  793. void *p;
  794. {
  795.     struct mbx *m;
  796.     char sock[MAXSOCKSIZE], *np, alias[AXBUF];
  797.     union sp sp;
  798.     int len;
  799.     m = (struct mbx *)p;
  800.     sp.p = sock;
  801.     if(argc < 2)
  802.         return -1;
  803.     switch(*argv[0]) {
  804.     case 't':
  805.         sp.in->sin_family = AF_INET;
  806.         if((sp.in->sin_addr.s_addr = resolve(argv[1])) == 0)
  807.             return -1;
  808.         /* get the optional port number */
  809.         if(argc > 2)
  810.             sp.in->sin_port = atoi(argv[2]);
  811.         else
  812.             sp.in->sin_port = IPPORT_TELNET;
  813.         if((m->user = socket(AF_INET,SOCK_STREAM,0)) == -1)
  814.             return -1;
  815.         len = sizeof(*sp.in);
  816.         break;
  817. #ifdef AX25
  818.     case 'a':
  819.     case 'c':    /* allow 'c' for 'connect' as well */
  820.         if(argc < 3)
  821.             return -1;
  822.         sp.ax->sax_family = AF_AX25;
  823.         strncpy(sp.ax->iface,argv[1],ILEN); /* the interface name */
  824.         setcall(sp.ax->ax25_addr,argv[2]); /* the remote callsign */
  825.         /* no digipeaters for now, use the "ax25 route add" command */
  826.         if((m->user = socket(AF_AX25,SOCK_STREAM,0)) == -1)
  827.             return -1;
  828.         len = sizeof(*sp.ax);
  829.         break;
  830. #endif /* AX25 */
  831. #ifdef NETROM
  832.     case 'n':
  833.         sp.nr->nr_family = AF_NETROM;
  834.         len = sizeof(*sp.nr);
  835.         if((m->user = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1)
  836.             return -1;
  837.         memcpy(sp.nr->nr_addr.user,Nr4user,AXALEN);
  838.         memcpy(sp.nr->nr_addr.node,Mycall,AXALEN);
  839.         bind(m->user,sp.p,len);
  840.         /* See if the requested destination could be an alias, and
  841.          * use it if it is.  Otherwise assume it is an AX.25
  842.          * address.
  843.          */
  844.         if (putalias(alias,argv[1],0) != -1 &&
  845.             (np = find_nralias(alias)) != NULLCHAR) {
  846.                 memcpy(sp.nr->nr_addr.user,np,AXALEN) ;
  847.                 memcpy(sp.nr->nr_addr.node,np,AXALEN) ;
  848.         }
  849.         else {    /* parse ax25 callsign */
  850.         /* Only the user callsign of the remote station is never
  851.          * used by NET/ROM, but it is needed for the psocket() call.
  852.          */
  853.             setcall(sp.nr->nr_addr.user,argv[1]);
  854.             setcall(sp.nr->nr_addr.node,argv[1]);
  855.         }
  856.         break;
  857. #endif /* NETROM */
  858.     default:
  859.         return -1;
  860.     }
  861.     sockmode(m->user,SOCK_ASCII);
  862.     if(connect(m->user,sp.p,len) == -1) {
  863.         log(m->user,"MBOX forward failed: %s errno %d",
  864.                 sockerr(m->user),errno);
  865.         close_s(m->user);
  866.         return -1;
  867.     }
  868.     return m->user;
  869. }
  870.